From 13db2d8338d734ec20d803e49d2453e3b928455b Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Sat, 29 Jan 2022 13:24:46 -0700 Subject: [PATCH] Convert gtrnctr to Format class (#839) * Convert gtrnctr to Format class * fix includes * make ingorelist const --- CMakeLists.txt | 1 + GPSBabel.pro | 1 + gtrnctr.cc | 332 ++++++++++++++++--------------------------------- gtrnctr.h | 235 ++++++++++++++++++++++++++++++++++ vecs.h | 4 +- 5 files changed, 343 insertions(+), 230 deletions(-) create mode 100644 gtrnctr.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c5539f4a5..cb48a65fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -240,6 +240,7 @@ set(HEADERS globalsat_sport.h gpx.h grtcirc.h + gtrnctr.h heightgrid.h holux.h html.h diff --git a/GPSBabel.pro b/GPSBabel.pro index e4ba04ad7..9957d9f4f 100644 --- a/GPSBabel.pro +++ b/GPSBabel.pro @@ -227,6 +227,7 @@ HEADERS = \ globalsat_sport.h \ gpx.h \ grtcirc.h \ + gtrnctr.h \ heightgrid.h \ holux.h \ html.h \ diff --git a/gtrnctr.cc b/gtrnctr.cc index 693199fd1..bc6aa0934 100644 --- a/gtrnctr.cc +++ b/gtrnctr.cc @@ -24,174 +24,51 @@ * http://www8.garmin.com/xmlschemas/ActivityExtensionv2.xsd */ -#include +#include "gtrnctr.h" -#include "defs.h" -#include "xmlgeneric.h" -#include +#include // for QByteArray +#include // for QDateTime +#include // for qPrintable +#include // for QXmlStreamAttributes + +#include // for va_end, va_list, va_start +#include // for snprintf +#include // for atoi +#include // for size +#include // for optional +#include // for add_const<>::type + +#include "defs.h" // for Waypoint, route_head, computed_trkdata, waypt_add, route_disp, track_disp_all, case_ignore_strncmp, track_add_head, track_add_wpt, track_recompute, xml_parse_time, CSTR, wp_flags, WAYPT_SET, unknown_alt +#include "xmlgeneric.h" // for xg_string, build_xg_tag_map, xml_deinit, xml_init, xml_read -static gbfile* ofd; -static int lap_ct = 0; -static int lap_s = 0; -static Waypoint* wpt_tmp; -static route_head* trk_head; #define MYNAME "gtc" -#define GTC_MAX_NAME_LEN 15 - -#define MAX_SPORTS 4 -static char gtc_sportlist[MAX_SPORTS][16] = { "Biking", "Running", "MultiSport", "Other" }; -static int gtc_sport = 0; -static int gtc_course_flag; - -static gpsbabel::DateTime gtc_least_time; -static gpsbabel::DateTime gtc_most_time; -static double gtc_start_lat; -static double gtc_start_long; -static double gtc_end_lat; -static double gtc_end_long; - -static char* opt_sport, *opt_course; - -static -QVector gtc_args = { - { - "course", &opt_course, "Write course rather than history, default yes", - "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr - }, - { - "sport", &opt_sport, "Sport: Biking (deflt), Running, MultiSport, Other", - "Biking", ARGTYPE_STRING, ARG_NOMINMAX, nullptr - }, -}; - -/* Tracks */ -static xg_callback gtc_trk_s; -static xg_callback gtc_trk_ident; -static xg_callback gtc_trk_lap_s, gtc_trk_lap_e; -static xg_callback gtc_trk_pnt_s, gtc_trk_pnt_e; -static xg_callback gtc_trk_utc; -static xg_callback gtc_trk_lat; -static xg_callback gtc_trk_long; -static xg_callback gtc_trk_alt; -static xg_callback gtc_trk_dist; -static xg_callback gtc_trk_hr; -static xg_callback gtc_trk_cad; -static xg_callback gtc_trk_pwr; -static xg_callback gtc_trk_spd; -static xg_callback gtc_wpt_crs_s, gtc_wpt_crs_e; -static xg_callback gtc_wpt_pnt_s, gtc_wpt_pnt_e; -static xg_callback gtc_wpt_ident; -static xg_callback gtc_wpt_lat; -static xg_callback gtc_wpt_long; -static xg_callback gtc_wpt_icon; -static xg_callback gtc_wpt_notes; - -static xg_tag_mapping gtc_map[] = { - /* courses tcx v1 & v2 */ - { gtc_trk_s, cb_start, "/Courses/Course" }, - { gtc_trk_ident,cb_cdata, "/Courses/Course/Name"}, - { gtc_trk_pnt_s,cb_start, "/Courses/Course/Track/Trackpoint" }, - { gtc_trk_pnt_e,cb_end, "/Courses/Course/Track/Trackpoint" }, - { gtc_trk_utc, cb_cdata, "/Courses/Course/Track/Trackpoint/Time" }, - { gtc_trk_lat, cb_cdata, "/Courses/Course/Track/Trackpoint/Position/LatitudeDegrees" }, - { gtc_trk_long, cb_cdata, "/Courses/Course/Track/Trackpoint/Position/LongitudeDegrees" }, - { gtc_trk_alt, cb_cdata, "/Courses/Course/Track/Trackpoint/AltitudeMeters" }, - { gtc_trk_hr, cb_cdata, "/Courses/Course/Track/Trackpoint/HeartRateBpm" }, - { gtc_trk_cad, cb_cdata, "/Courses/Course/Track/Trackpoint/Cadence" }, - { gtc_wpt_crs_s,cb_start, "/Courses/Course/CoursePoint" }, - { gtc_wpt_crs_e,cb_end, "/Courses/Course/CoursePoint" }, - { gtc_wpt_ident,cb_cdata, "/Courses/Course/CoursePoint/Name"}, - { gtc_trk_utc, cb_cdata, "/Courses/Course/CoursePoint/Time"}, - { gtc_wpt_lat, cb_cdata, "/Courses/Course/CoursePoint/Position/LatitudeDegrees"}, - { gtc_wpt_long, cb_cdata, "/Courses/Course/CoursePoint/Position/LongitudeDegrees"}, - { gtc_trk_alt, cb_cdata, "/Courses/Course/CoursePoint/AltitudeMeters" }, - { gtc_wpt_icon, cb_cdata, "/Courses/Course/CoursePoint/PointType" }, - { gtc_wpt_notes,cb_cdata, "/Courses/Course/CoursePoint/Notes" }, - - /* history tcx v2 (activities) */ - { gtc_trk_s, cb_start, "/Activities/Activity" }, - { gtc_trk_ident,cb_cdata, "/Activities/Activity/Id" }, - { gtc_trk_lap_s,cb_start, "/Activities/Activity/Lap" }, - { gtc_trk_lap_e,cb_end, "/Activities/Activity/Lap" }, - { gtc_trk_pnt_s,cb_start, "/Activities/Activity/Lap/Track/Trackpoint" }, - { gtc_trk_pnt_e,cb_end, "/Activities/Activity/Lap/Track/Trackpoint" }, - { gtc_trk_utc, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Time" }, - { gtc_trk_lat, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Position/LatitudeDegrees" }, - { gtc_trk_long, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Position/LongitudeDegrees" }, - { gtc_trk_alt, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/AltitudeMeters" }, - { gtc_trk_dist, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/DistanceMeters" }, - { gtc_trk_hr, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/HeartRateBpm" }, - { gtc_trk_cad, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Cadence" }, - { gtc_trk_pwr, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Extensions/ns3:TPX/ns3:Watts" }, - // Sample from Marcelo Kittlein 5/2014 declares a default namespace with the start tag of the TPX element, - // and thus doesn't use prefixes. - { gtc_trk_pwr, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Extensions/TPX/Watts" }, - // It looks like Speed and Watts should be siblings, but Garmin can't get - // their namespace act very consistent. This works for a sample provided - // by Laurent Desmons in 5/2013. - { gtc_trk_spd, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Extensions/TPX/Speed" }, - - /* history tcx v1 */ - { gtc_trk_s, cb_start, "/History/Run" }, - { gtc_trk_ident,cb_cdata, "/History/Run/Id" }, - { gtc_trk_lap_s,cb_start, "/History/Run/Lap" }, - { gtc_trk_lap_e,cb_end, "/History/Run/Lap" }, - { gtc_trk_pnt_s,cb_start, "/History/Run/Lap/Track/Trackpoint" }, - { gtc_trk_pnt_e,cb_end, "/History/Run/Lap/Track/Trackpoint" }, - { gtc_trk_utc, cb_cdata, "/History/Run/Lap/Track/Trackpoint/Time" }, - { gtc_trk_lat, cb_cdata, "/History/Run/Lap/Track/Trackpoint/Position/LatitudeDegrees" }, - { gtc_trk_long, cb_cdata, "/History/Run/Lap/Track/Trackpoint/Position/LongitudeDegrees" }, - { gtc_trk_alt, cb_cdata, "/History/Run/Lap/Track/Trackpoint/AltitudeMeters" }, - { gtc_trk_hr, cb_cdata, "/History/Run/Lap/Track/Trackpoint/HeartRateBpm" }, - { gtc_trk_cad, cb_cdata, "/History/Run/Lap/Track/Trackpoint/Cadence" }, - - { gtc_wpt_pnt_s,cb_start, "/Courses/Course/Lap/BeginPosition" }, - { gtc_wpt_pnt_e,cb_end, "/Courses/Course/Lap/BeginPosition" }, - { gtc_wpt_lat, cb_cdata, "/Courses/Course/Lap/BeginPosition/LatitudeDegrees" }, - { gtc_wpt_long, cb_cdata, "/Courses/Course/Lap/BeginPosition/LongitudeDegrees" }, - { gtc_trk_alt, cb_cdata, "/Courses/Course/Lap/BeginAltitudeMeters" }, - - { nullptr, (xg_cb_type)0, nullptr} -}; - -static const char* -gtc_tags_to_ignore[] = { - "TrainingCenterDatabase", - "CourseFolder", - "Running", - "Biking", - "Other", - "Multisport", - nullptr, -}; - -static void -gtc_rd_init(const QString& fname) -{ - xml_init(fname, gtc_map, nullptr, gtc_tags_to_ignore); -} - -static void -gtc_read() +void +GtrnctrFormat::rd_init(const QString& fname) +{ + xml_init(fname, build_xg_tag_map(this, gtc_map), nullptr, gtc_tags_to_ignore, nullptr, true); +} + +void +GtrnctrFormat::read() { xml_read(); } -static void -gtc_rd_deinit() +void +GtrnctrFormat::rd_deinit() { xml_deinit(); } -static void -gtc_wr_init(const QString& fname) +void +GtrnctrFormat::wr_init(const QString& fname) { ofd = gbfopen(fname, "w", MYNAME); if (opt_sport) { - for (int i = 0; i < MAX_SPORTS; i++) { + for (unsigned int i = 0; i < std::size(gtc_sportlist); i++) { if (0 == case_ignore_strncmp(opt_sport, gtc_sportlist[i], 2)) { gtc_sport = i; break; @@ -201,16 +78,14 @@ gtc_wr_init(const QString& fname) gtc_course_flag = atoi(opt_course); } -static void -gtc_wr_deinit() +void +GtrnctrFormat::wr_deinit() { gbfclose(ofd); } -static int gtc_indent_level; - -static void -gtc_write_xml(int indent, const char* fmt, ...) +void +GtrnctrFormat::gtc_write_xml(int indent, const char* fmt, ...) { va_list args; @@ -230,8 +105,8 @@ gtc_write_xml(int indent, const char* fmt, ...) va_end(args); } -static void -gtc_write_xml(int indent, const QString& s) +void +GtrnctrFormat::gtc_write_xml(int indent, const QString& s) { if (indent < 0) { gtc_indent_level--; @@ -245,21 +120,21 @@ gtc_write_xml(int indent, const QString& s) } -static void -gtc_lap_start(const route_head*) +void +GtrnctrFormat::gtc_lap_start(const route_head* /*unused*/) { gtc_least_time = gpsbabel::DateTime(); gtc_most_time = gpsbabel::DateTime(); } -static computed_trkdata -gtc_new_study_lap(const route_head* rte) +computed_trkdata +GtrnctrFormat::gtc_new_study_lap(const route_head* rte) { return track_recompute(rte); } -static void -gtc_study_lap(const Waypoint* wpt) +void +GtrnctrFormat::gtc_study_lap(const Waypoint* wpt) { if (wpt->creation_time.isValid() && (!gtc_least_time.isValid())) { gtc_least_time = wpt->GetCreationTime(); @@ -279,8 +154,8 @@ gtc_study_lap(const Waypoint* wpt) } } -static void -gtc_waypt_pr(const Waypoint* wpt) +void +GtrnctrFormat::gtc_waypt_pr(const Waypoint* wpt) { if (wpt->wpt_flags.is_split != 0) { gtc_write_xml(1, "\n"); @@ -335,8 +210,8 @@ gtc_waypt_pr(const Waypoint* wpt) gtc_write_xml(-1, "\n"); } -static void -gtc_fake_hdr(const computed_trkdata& tdata) +void +GtrnctrFormat::gtc_fake_hdr(const computed_trkdata& tdata) { /* handle the CourseLap_t or the ActivityLap_t types. */ /* note that the elements must appear in the order required by the schema. */ @@ -387,13 +262,16 @@ gtc_fake_hdr(const computed_trkdata& tdata) } -static void -gtc_act_hdr(const route_head* rte) +void +GtrnctrFormat::gtc_act_hdr(const route_head* rte) { gtc_write_xml(1, "\n", gtc_sportlist[gtc_sport]); gtc_lap_start(nullptr); computed_trkdata tdata = gtc_new_study_lap(rte); - route_disp(rte, gtc_study_lap); + auto gtc_study_lap_lambda = [this](const Waypoint* waypointp)->void { + gtc_study_lap(waypointp); + }; + route_disp(rte, gtc_study_lap_lambda); if (gtc_least_time.isValid()) { gtc_write_xml(0, "%s\n", CSTR(gtc_least_time.toPrettyString())); @@ -406,25 +284,28 @@ gtc_act_hdr(const route_head* rte) gtc_write_xml(1,"\n"); } -static void -gtc_act_ftr(const route_head*) +void +GtrnctrFormat::gtc_act_ftr(const route_head* /*unused*/) { gtc_write_xml(-1, "\n"); gtc_write_xml(-1, "\n"); gtc_write_xml(-1, "\n"); } -static void -gtc_crs_hdr(const route_head* rte) +void +GtrnctrFormat::gtc_crs_hdr(const route_head* rte) { gtc_write_xml(1, "\n"); gtc_lap_start(nullptr); computed_trkdata tdata = gtc_new_study_lap(rte); - route_disp(rte, gtc_study_lap); + auto gtc_study_lap_lambda = [this](const Waypoint* waypointp)->void { + gtc_study_lap(waypointp); + }; + route_disp(rte, gtc_study_lap_lambda); if (!rte->rte_name.isEmpty()) { - QString name = rte->rte_name.left(GTC_MAX_NAME_LEN); + QString name = rte->rte_name.left(kGtcMaxNameLen); gtc_write_xml(0, QString("%1\n").arg(name)); } else { gtc_write_xml(0, "New Course\n"); @@ -436,27 +317,42 @@ gtc_crs_hdr(const route_head* rte) gtc_write_xml(1,"\n"); } -static void -gtc_crs_ftr(const route_head*) +void +GtrnctrFormat::gtc_crs_ftr(const route_head* /*unused*/) { gtc_write_xml(-1,"\n"); gtc_write_xml(-1, "\n"); } -static void -gtc_write() +void +GtrnctrFormat::write() { gtc_write_xml(0, "\n"); gtc_write_xml(1, "\n"); + auto gtc_waypt_pr_lambda = [this](const Waypoint* waypointp)->void { + gtc_waypt_pr(waypointp); + }; if (gtc_course_flag) { gtc_write_xml(1, "\n"); - track_disp_all(gtc_crs_hdr, gtc_crs_ftr, gtc_waypt_pr); + auto gtc_crs_hdr_lambda = [this](const route_head* rte)->void { + gtc_crs_hdr(rte); + }; + auto gtc_crs_ftr_lambda = [this](const route_head* rte)->void { + gtc_crs_ftr(rte); + }; + track_disp_all(gtc_crs_hdr_lambda, gtc_crs_ftr_lambda, gtc_waypt_pr_lambda); gtc_write_xml(-1, "\n"); } else { gtc_write_xml(1, "\n"); - track_disp_all(gtc_act_hdr, gtc_act_ftr, gtc_waypt_pr); + auto gtc_act_hdr_lambda = [this](const route_head* rte)->void { + gtc_act_hdr(rte); + }; + auto gtc_act_ftr_lambda = [this](const route_head* rte)->void { + gtc_act_ftr(rte); + }; + track_disp_all(gtc_act_hdr_lambda, gtc_act_ftr_lambda, gtc_waypt_pr_lambda); gtc_write_xml(-1, "\n"); } @@ -464,39 +360,39 @@ gtc_write() } void -gtc_trk_s(xg_string, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_trk_s(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) { trk_head = new route_head; track_add_head(trk_head); } void -gtc_trk_ident(xg_string args, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_trk_ident(xg_string args, const QXmlStreamAttributes* /*unused*/) { trk_head->rte_name = args; } void -gtc_trk_lap_s(xg_string, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_trk_lap_s(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) { lap_ct++; lap_s = 1; } void -gtc_trk_lap_e(xg_string, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_trk_lap_e(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) { lap_s = 0; } void -gtc_trk_pnt_s(xg_string, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_trk_pnt_s(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) { wpt_tmp = new Waypoint; } void -gtc_trk_pnt_e(xg_string, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_trk_pnt_e(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) { if (wpt_tmp->longitude != 0. && wpt_tmp->latitude != 0.) { if (lap_s) { @@ -519,62 +415,62 @@ gtc_trk_pnt_e(xg_string, const QXmlStreamAttributes*) } void -gtc_trk_utc(xg_string args, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_trk_utc(xg_string args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->creation_time = xml_parse_time(args); } void -gtc_trk_lat(xg_string args, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_trk_lat(xg_string args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->latitude = args.toDouble(); } void -gtc_trk_long(xg_string args, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_trk_long(xg_string args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->longitude = args.toDouble(); } void -gtc_trk_alt(xg_string args, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_trk_alt(xg_string args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->altitude = args.toDouble(); } -void gtc_trk_dist(const QString& args, const QXmlStreamAttributes*) +void GtrnctrFormat::gtc_trk_dist(const QString& args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->odometer_distance = args.toDouble(); } -void gtc_trk_hr(const QString& args, const QXmlStreamAttributes*) +void GtrnctrFormat::gtc_trk_hr(const QString& args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->heartrate = args.toDouble(); } -void gtc_trk_cad(const QString& args, const QXmlStreamAttributes*) +void GtrnctrFormat::gtc_trk_cad(const QString& args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->cadence = args.toDouble(); } void -gtc_trk_pwr(xg_string args, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_trk_pwr(xg_string args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->power = args.toDouble(); } void -gtc_trk_spd(xg_string args, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_trk_spd(xg_string args, const QXmlStreamAttributes* /*unused*/) { WAYPT_SET(wpt_tmp, speed, args.toDouble()); } void -gtc_wpt_crs_s(const QString&, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_wpt_crs_s(const QString& /*unused*/, const QXmlStreamAttributes* /*unused*/) { wpt_tmp = new Waypoint; } void -gtc_wpt_crs_e(xg_string, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_wpt_crs_e(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) { if (wpt_tmp->longitude != 0. && wpt_tmp->latitude != 0.) { waypt_add(wpt_tmp); @@ -586,14 +482,14 @@ gtc_wpt_crs_e(xg_string, const QXmlStreamAttributes*) } void -gtc_wpt_pnt_s(xg_string, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_wpt_pnt_s(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) { wpt_tmp = new Waypoint; lap_ct++; } void -gtc_wpt_pnt_e(xg_string, const QXmlStreamAttributes*) +GtrnctrFormat::gtc_wpt_pnt_e(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) { if (wpt_tmp->longitude != 0. && wpt_tmp->latitude != 0.) { /* Add the begin position of a CourseLap as @@ -607,45 +503,25 @@ gtc_wpt_pnt_e(xg_string, const QXmlStreamAttributes*) wpt_tmp = nullptr; } -void gtc_wpt_ident(const QString& args, const QXmlStreamAttributes*) +void GtrnctrFormat::gtc_wpt_ident(const QString& args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->shortname = (args); /* Set also as notes for compatibility with garmin usb format */ wpt_tmp->notes = (args); } -void gtc_wpt_lat(const QString& args, const QXmlStreamAttributes*) +void GtrnctrFormat::gtc_wpt_lat(const QString& args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->latitude = args.toDouble(); } -void gtc_wpt_long(const QString& args, const QXmlStreamAttributes*) +void GtrnctrFormat::gtc_wpt_long(const QString& args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->longitude = args.toDouble(); } -void gtc_wpt_icon(const QString& args, const QXmlStreamAttributes*) +void GtrnctrFormat::gtc_wpt_icon(const QString& args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->icon_descr = args; } -void gtc_wpt_notes(const QString& args, const QXmlStreamAttributes*) +void GtrnctrFormat::gtc_wpt_notes(const QString& args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->description = args; } - -ff_vecs_t gtc_vecs = { - ff_type_file, - { - ff_cap_read /* waypoints */, - (ff_cap)(ff_cap_read | ff_cap_write) /* tracks */, - ff_cap_none /* routes */ - }, - gtc_rd_init, - gtc_wr_init, - gtc_rd_deinit, - gtc_wr_deinit, - gtc_read, - gtc_write, - nullptr, - >c_args, - CET_CHARSET_ASCII, 0 /* CET-REVIEW */ - , NULL_POS_OPS, - nullptr -}; diff --git a/gtrnctr.h b/gtrnctr.h new file mode 100644 index 000000000..1971e7a04 --- /dev/null +++ b/gtrnctr.h @@ -0,0 +1,235 @@ +/* + Access Garmin Training Center (Forerunner/Foretracker/Edge) data files. + + Copyright (C) 2006, 2007 Robert Lipe, robertlipe+source@gpsbabel.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + */ +/* + * Relevant schema definitions can be found at + * http://www8.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd + * http://www8.garmin.com/xmlschemas/ActivityExtensionv2.xsd + */ +#ifndef GTRNCTR_H_INCLUDED_ +#define GTRNCTR_H_INCLUDED_ + +#include // for QList +#include // for QString +#include // for QVector +#include // for QXmlStreamAttributes + +#include "defs.h" // for arglist_t, ff_cap, route_head, Waypoint, computed_trkdata, ARG_NOMINMAX, ff_cap_read, ARGTYPE_BOOL, ARGTYPE_STRING, CET_CHARSET_ASCII, ff_cap_none, ff_cap_write, ff_type, ff_type_file +#include "format.h" // for Format +#include "gbfile.h" // for gbfile +#include "src/core/datetime.h" // for DateTime +#include "xmlgeneric.h" // for cb_cdata, xg_functor_map_entry, xg_string, cb_start, cb_end + + +class GtrnctrFormat : public Format +{ +public: + QVector* get_args() override + { + return >c_args; + } + + ff_type get_type() const override + { + return ff_type_file; + } + + QVector get_cap() const override + { + return { + ff_cap_read /* waypoints */, + (ff_cap)(ff_cap_read | ff_cap_write) /* tracks */, + ff_cap_none /* routes */ + }; + } + + QString get_encode() const override + { + return CET_CHARSET_ASCII; + } + + int get_fixed_encode() const override + { + return 0; + } + + void rd_init(const QString& fname) override; + void read() override; + void rd_deinit() override; + void wr_init(const QString& fname) override; + void write() override; + void wr_deinit() override; + +private: + /* Constants */ + + static constexpr int kGtcMaxNameLen = 15; + static constexpr const char* gtc_sportlist[] = { "Biking", "Running", "MultiSport", "Other" }; + + static constexpr const char* gtc_tags_to_ignore[] = { + "TrainingCenterDatabase", + "CourseFolder", + "Running", + "Biking", + "Other", + "Multisport", + nullptr, + }; + + /* Member Functions */ + + void gtc_write_xml(int indent, const char* fmt, ...); + void gtc_write_xml(int indent, const QString& s); + void gtc_lap_start(const route_head* /* unused */); + static computed_trkdata gtc_new_study_lap(const route_head* rte); + void gtc_study_lap(const Waypoint* wpt); + void gtc_waypt_pr(const Waypoint* wpt); + void gtc_fake_hdr(const computed_trkdata& tdata); + void gtc_act_hdr(const route_head* rte); + void gtc_act_ftr(const route_head* /* unused */); + void gtc_crs_hdr(const route_head* rte); + void gtc_crs_ftr(const route_head* /* unused */); + + void gtc_trk_s(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_trk_ident(xg_string args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_lap_s(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_trk_lap_e(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_trk_pnt_s(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_trk_pnt_e(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_trk_utc(xg_string args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_lat(xg_string args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_long(xg_string args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_alt(xg_string args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_dist(const QString& args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_hr(const QString& args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_cad(const QString& args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_pwr(xg_string args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_spd(xg_string args, const QXmlStreamAttributes* /* unused */); + void gtc_wpt_crs_s(const QString& /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_wpt_crs_e(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_wpt_pnt_s(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_wpt_pnt_e(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_wpt_ident(const QString& args, const QXmlStreamAttributes* /* unused */); + void gtc_wpt_lat(const QString& args, const QXmlStreamAttributes* /* unused */); + void gtc_wpt_long(const QString& args, const QXmlStreamAttributes* /* unused */); + void gtc_wpt_icon(const QString& args, const QXmlStreamAttributes* /* unused */); + void gtc_wpt_notes(const QString& args, const QXmlStreamAttributes* /* unused */); + + /* Data Members */ + + gbfile* ofd{}; + int lap_ct = 0; + int lap_s = 0; + Waypoint* wpt_tmp{}; + route_head* trk_head{}; + + unsigned int gtc_sport = 0; + int gtc_course_flag{}; + + gpsbabel::DateTime gtc_least_time; + gpsbabel::DateTime gtc_most_time; + double gtc_start_lat{}; + double gtc_start_long{}; + double gtc_end_lat{}; + double gtc_end_long{}; + + char* opt_sport{}; + char* opt_course{}; + + QVector gtc_args = { + { + "course", &opt_course, "Write course rather than history, default yes", + "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr + }, + { + "sport", &opt_sport, "Sport: Biking (deflt), Running, MultiSport, Other", + "Biking", ARGTYPE_STRING, ARG_NOMINMAX, nullptr + }, + }; + + QList> gtc_map = { + /* courses tcx v1 & v2 */ + { &GtrnctrFormat::gtc_trk_s, cb_start, "/Courses/Course" }, + { &GtrnctrFormat::gtc_trk_ident,cb_cdata, "/Courses/Course/Name"}, + { &GtrnctrFormat::gtc_trk_pnt_s,cb_start, "/Courses/Course/Track/Trackpoint" }, + { &GtrnctrFormat::gtc_trk_pnt_e,cb_end, "/Courses/Course/Track/Trackpoint" }, + { &GtrnctrFormat::gtc_trk_utc, cb_cdata, "/Courses/Course/Track/Trackpoint/Time" }, + { &GtrnctrFormat::gtc_trk_lat, cb_cdata, "/Courses/Course/Track/Trackpoint/Position/LatitudeDegrees" }, + { &GtrnctrFormat::gtc_trk_long, cb_cdata, "/Courses/Course/Track/Trackpoint/Position/LongitudeDegrees" }, + { &GtrnctrFormat::gtc_trk_alt, cb_cdata, "/Courses/Course/Track/Trackpoint/AltitudeMeters" }, + { &GtrnctrFormat::gtc_trk_hr, cb_cdata, "/Courses/Course/Track/Trackpoint/HeartRateBpm" }, + { &GtrnctrFormat::gtc_trk_cad, cb_cdata, "/Courses/Course/Track/Trackpoint/Cadence" }, + { &GtrnctrFormat::gtc_wpt_crs_s,cb_start, "/Courses/Course/CoursePoint" }, + { &GtrnctrFormat::gtc_wpt_crs_e,cb_end, "/Courses/Course/CoursePoint" }, + { &GtrnctrFormat::gtc_wpt_ident,cb_cdata, "/Courses/Course/CoursePoint/Name"}, + { &GtrnctrFormat::gtc_trk_utc, cb_cdata, "/Courses/Course/CoursePoint/Time"}, + { &GtrnctrFormat::gtc_wpt_lat, cb_cdata, "/Courses/Course/CoursePoint/Position/LatitudeDegrees"}, + { &GtrnctrFormat::gtc_wpt_long, cb_cdata, "/Courses/Course/CoursePoint/Position/LongitudeDegrees"}, + { &GtrnctrFormat::gtc_trk_alt, cb_cdata, "/Courses/Course/CoursePoint/AltitudeMeters" }, + { &GtrnctrFormat::gtc_wpt_icon, cb_cdata, "/Courses/Course/CoursePoint/PointType" }, + { &GtrnctrFormat::gtc_wpt_notes,cb_cdata, "/Courses/Course/CoursePoint/Notes" }, + + /* history tcx v2 (activities) */ + { &GtrnctrFormat::gtc_trk_s, cb_start, "/Activities/Activity" }, + { &GtrnctrFormat::gtc_trk_ident,cb_cdata, "/Activities/Activity/Id" }, + { &GtrnctrFormat::gtc_trk_lap_s,cb_start, "/Activities/Activity/Lap" }, + { &GtrnctrFormat::gtc_trk_lap_e,cb_end, "/Activities/Activity/Lap" }, + { &GtrnctrFormat::gtc_trk_pnt_s,cb_start, "/Activities/Activity/Lap/Track/Trackpoint" }, + { &GtrnctrFormat::gtc_trk_pnt_e,cb_end, "/Activities/Activity/Lap/Track/Trackpoint" }, + { &GtrnctrFormat::gtc_trk_utc, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Time" }, + { &GtrnctrFormat::gtc_trk_lat, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Position/LatitudeDegrees" }, + { &GtrnctrFormat::gtc_trk_long, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Position/LongitudeDegrees" }, + { &GtrnctrFormat::gtc_trk_alt, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/AltitudeMeters" }, + { &GtrnctrFormat::gtc_trk_dist, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/DistanceMeters" }, + { &GtrnctrFormat::gtc_trk_hr, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/HeartRateBpm" }, + { &GtrnctrFormat::gtc_trk_cad, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Cadence" }, + { &GtrnctrFormat::gtc_trk_pwr, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Extensions/ns3:TPX/ns3:Watts" }, + // Sample from Marcelo Kittlein 5/2014 declares a default namespace with the start tag of the TPX element, + // and thus doesn't use prefixes. + { &GtrnctrFormat::gtc_trk_pwr, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Extensions/TPX/Watts" }, + // It looks like Speed and Watts should be siblings, but Garmin can't get + // their namespace act very consistent. This works for a sample provided + // by Laurent Desmons in 5/2013. + { &GtrnctrFormat::gtc_trk_spd, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Extensions/TPX/Speed" }, + + /* history tcx v1 */ + { &GtrnctrFormat::gtc_trk_s, cb_start, "/History/Run" }, + { &GtrnctrFormat::gtc_trk_ident,cb_cdata, "/History/Run/Id" }, + { &GtrnctrFormat::gtc_trk_lap_s,cb_start, "/History/Run/Lap" }, + { &GtrnctrFormat::gtc_trk_lap_e,cb_end, "/History/Run/Lap" }, + { &GtrnctrFormat::gtc_trk_pnt_s,cb_start, "/History/Run/Lap/Track/Trackpoint" }, + { &GtrnctrFormat::gtc_trk_pnt_e,cb_end, "/History/Run/Lap/Track/Trackpoint" }, + { &GtrnctrFormat::gtc_trk_utc, cb_cdata, "/History/Run/Lap/Track/Trackpoint/Time" }, + { &GtrnctrFormat::gtc_trk_lat, cb_cdata, "/History/Run/Lap/Track/Trackpoint/Position/LatitudeDegrees" }, + { &GtrnctrFormat::gtc_trk_long, cb_cdata, "/History/Run/Lap/Track/Trackpoint/Position/LongitudeDegrees" }, + { &GtrnctrFormat::gtc_trk_alt, cb_cdata, "/History/Run/Lap/Track/Trackpoint/AltitudeMeters" }, + { &GtrnctrFormat::gtc_trk_hr, cb_cdata, "/History/Run/Lap/Track/Trackpoint/HeartRateBpm" }, + { &GtrnctrFormat::gtc_trk_cad, cb_cdata, "/History/Run/Lap/Track/Trackpoint/Cadence" }, + + { &GtrnctrFormat::gtc_wpt_pnt_s,cb_start, "/Courses/Course/Lap/BeginPosition" }, + { &GtrnctrFormat::gtc_wpt_pnt_e,cb_end, "/Courses/Course/Lap/BeginPosition" }, + { &GtrnctrFormat::gtc_wpt_lat, cb_cdata, "/Courses/Course/Lap/BeginPosition/LatitudeDegrees" }, + { &GtrnctrFormat::gtc_wpt_long, cb_cdata, "/Courses/Course/Lap/BeginPosition/LongitudeDegrees" }, + { &GtrnctrFormat::gtc_trk_alt, cb_cdata, "/Courses/Course/Lap/BeginAltitudeMeters" } + }; + + int gtc_indent_level{}; +}; +#endif // GTRNCTR_H_INCLUDED_ diff --git a/vecs.h b/vecs.h index cc78d25bc..6afa0e04c 100644 --- a/vecs.h +++ b/vecs.h @@ -37,6 +37,7 @@ #include "ggv_bin.h" #include "globalsat_sport.h" #include "gpx.h" +#include "gtrnctr.h" #include "html.h" #include "kml.h" #include "legacyformat.h" @@ -95,7 +96,6 @@ extern ff_vecs_t gpssim_vecs; #if CSVFMTS_ENABLED extern ff_vecs_t garmin_txt_vecs; #endif // CSVFMTS_ENABLED -extern ff_vecs_t gtc_vecs; extern ff_vecs_t dmtlog_vecs; extern ff_vecs_t raymarine_vecs; extern ff_vecs_t ggv_log_vecs; @@ -278,7 +278,7 @@ private: #if CSVFMTS_ENABLED LegacyFormat garmin_txt_fmt {garmin_txt_vecs}; #endif // CSVFMTS_ENABLED - LegacyFormat gtc_fmt {gtc_vecs}; + GtrnctrFormat gtc_fmt; LegacyFormat dmtlog_fmt {dmtlog_vecs}; LegacyFormat raymarine_fmt {raymarine_vecs}; LegacyFormat ggv_log_fmt {ggv_log_vecs}; -- 2.30.2